AddCSLuaFile("cl_init.lua")
AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include("shared.lua")

function ENT:UpdateTransmitState() return TRANSMIT_ALWAYS end

function ENT:Initialize()

	//Initialise Physics
	self.Entity:SetMoveType(MOVETYPE_NONE)
	self.Entity:SetSolid(SOLID_VPHYSICS)
	self.Entity:PhysicsInitSphere(self.Radius)
	self.Entity:DrawShadow(false)
	self.Entity:SetTrigger(true)
	self.Entity:SetNotSolid(true)
	local bounds = Vector(self.Radius,self.Radius,self.Radius)
	self.Entity:SetCollisionBounds(-1.25*bounds,1.25*bounds) --make the bounding-box slightly larger to make sure that (very) fast projectiles actually trigger Touch() before they are inside the dome
	
	self.Ignore = {}
	
	self.Entity:GetPhysicsObject():EnableCollisions(false)
	
	self.DomeClipPlanes = {}
	
	self.Entity:SetNetworkedInt("radius", self.Radius)
	self.Entity:SetNetworkedString("domematerial", self.DomeMaterial)
	self.Entity:SetNetworkedString("impactmaterial", self.ImpactEffect)
	self.Entity:SetNetworkedVector("impactcolor", self.ImpactColor)
	self.Entity:SetNetworkedString("projectorigin", self.Formdirection)
	
	self.Entity.CDamage = self.Entity.CDamage or {}
	self.Entity.CDamage.type = "shield"
	
	timer.Simple(0.1, function() if self.Entity:IsValid() then self.Entity:UpdateShieldsOnField(true) end end)
	
	self.Entity:NextThink(CurTime() + 0.5)
	
	--timer.Simple(0.1, function() if self.Entity:IsValid() then self.Entity:DrawDome() end end) //Create the Dome Visuals
end

function ENT:FacilitateImpact(entity)
	if self.Entity:IsValid() then
		self.Entity:Impact(entity:GetPos())
		if ((entity.CDamage != nil and entity.CDamage.projectile != nil) or entity.ImpactShield != nil) then //Checks if the projectile thinks it has an impact callback
			entity:ImpactShield(self.Entity) //Invokes the Projectile's Shield Impact Callback
		else
			
			if (entity:GetSolid() == 6) then
				self.Entity:GetParent():ReduceIntegrity(entity:GetPhysicsObject():GetMass() or 10) //Included for all those weapons who don't want to use my libraries. Inflicts damage based on projectile mass
			else
				self.Entity:GetParent():ReduceIntegrity(10)
			end
			entity:Remove()
		end
	end
end

function ENT:Touch(entity)
	if (entity:IsValid() && (entity:GetCollisionGroup() == COLLISION_GROUP_PROJECTILE || (string.find(entity:GetClass(), "launched_") == 1)) && (self.Ignore[entity] == nil)) then
		if CDamage_checkshieldintersect(entity:GetPos(), entity:GetVelocity(), nil, self.Entity) then //Because the shield is actually a cube, we need to check if the shot will intersect the ACTUAL dome rather than our cubic bounding-box
			self.Ignore[entity] = true
			local impactdistance = CDamage_shieldintersectdistance(entity:GetPos(), entity:GetVelocity(), self.Entity)
			local impactdelay = impactdistance / entity:GetVelocity():Length()
			timer.Simple(impactdelay, function() if entity:IsValid() && self.Entity:IsValid() then self.Entity:FacilitateImpact(entity) end end)
		else
			self.Ignore[entity] = true
		end
	end
end

function ENT:Think()
	local parent = self.Entity:GetParent()
	if not (parent and parent:IsValid() and parent.ReduceIntegrity) then
		self.Entity:Remove()
	end
end

function ENT:Impact(position)
	local efxdata = EffectData()
	local impactpoint = ((position - self.Entity:GetPos()):GetNormal() * self.Radius) + self.Entity:GetPos()
	efxdata:SetOrigin(self.Entity:GetPos())
	efxdata:SetEntity(self.Entity)
	efxdata:SetNormal((self.Entity:GetPos() - impactpoint):GetNormal())
	efxdata:SetMagnitude(250)
	efxdata:SetScale(1)
	util.Effect( "shield_impact", efxdata)
end

function ENT:ReduceIntegrity(damage)
	self.Entity:GetParent():ReduceIntegrity(damage)
end

function ENT:GetHP()
	return self.Entity:GetParent().HP
end

function ENT:DrawDome()
	local efxdata = EffectData()
	efxdata:SetOrigin(self.Entity:GetPos())
	efxdata:SetEntity(self.Entity)
	efxdata:SetMagnitude(self.Radius)
	util.Effect("shield_bubble", efxdata)
end

function ENT:UpdateShieldsOnField(includeself)
	local shields = ents.FindByClass("shield_dome")
	if (includeself) then
		self.Entity:SendUpdatedShields(shields)
	else
		for k, v in pairs(shields) do
			if (v == self.Entity) then
			table.remove(shields, k)
			end
		end
		self.Entity:SendUpdatedShields(shields)
	end
end

function ENT:SendUpdatedShields(shields)
	umsg.Start("shielddomeupdate")
		umsg.Long(#shields)
		for i=1, #shields do
			umsg.Entity(shields[i])
		end
	umsg.End()
end

function ENT:GetRadius()
	return self.Radius
end